﻿using System;

namespace SharpDepend.Classes
{
    public static class PeformanceHelper
    {
        /// <summary>
        /// A C# memset function.
        /// </summary>
        /// <param name="array">Array to do memset on.</param>
        /// <param name="offset">Offset in array.</param>
        /// <param name="length">Length to memset.</param>
        /// <param name="value">Value to set.</param>
        public static void MemSet(byte[] array, int offset, int length, byte value)
        {
            int block = 32;
            int index = 0;
            int length_ = Math.Min(block, length);

            // Fill the initial array.
            while (index < length_)
            {
                array[offset + index++] = value;
            }

            length_ = length;
            while (index < length_)
            {
                Buffer.BlockCopy(array, offset, array, (offset + index), Math.Min(block, length_ - index));
                index += block;
                block *= 2;
            }
        }

        /// <summary>
        /// A C# memset function.
        /// </summary>
        /// <param name="array">Array to do memset on.</param>
        /// <param name="offset">Offset in array.</param>
        /// <param name="length">Length to memset.</param>
        /// <param name="value">Value to set.</param>
        public static void MemSet(int[] array, int offset, int length, int value)
        {
            int block = 32;
            int index = 0;
            int length_ = Math.Min(block, length);

            // Fill the initial array.
            while (index < length_)
            {
                array[offset + index++] = value;
            }

            length_ = length;
            while (index < length_)
            {
                Buffer.BlockCopy(array, offset * sizeof(int), array, (offset + index) * sizeof(int), Math.Min(block, length_ - index) * sizeof(int));
                index += block;
                block *= 2;
            }
        }

        /// <summary>
        /// A C# memset function.
        /// </summary>
        /// <param name="array">Array to do memset on.</param>
        /// <param name="offset">Offset in array.</param>
        /// <param name="length">Length to memset.</param>
        /// <param name="value">Value to set.</param>
        public static void MemSet(double[] array, int offset, int length, double value)
        {
            int block = 32;
            int index = 0;
            int length_ = Math.Min(block, length);

            // Fill the initial array.
            while (index < length_)
            {
                array[offset + index++] = value;
            }

            length_ = length;
            while (index < length_)
            {
                Buffer.BlockCopy(array, offset * sizeof(double), array, (offset + index) * sizeof(double), Math.Min(block, length_ - index) * sizeof(double));
                index += block;
                block *= 2;
            }
        }

        public static object GetPrivateField<T>(Type type, string field, object fromInstance)
        {
            var audioClientField = type.GetField(field, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
            return (T)audioClientField.GetValue(fromInstance);
        }

        public static T GetProperty<T>(Type type, string property, object fromInstance, out bool ok)
        {
            ok = false;
            var prop = type.GetProperty(property);

            if (prop == null)
            {
                return default(T);
            }
            else
            {
                ok = true;
                return (T)prop.GetValue(fromInstance, null);
            }
        }


        public static uint NearestPowerOfTwo(uint x)
        {
            x--; // comment out to always take the next biggest power of two, even if x is already a power of two
            x |= (x >> 1);
            x |= (x >> 2);
            x |= (x >> 4);
            x |= (x >> 8);
            x |= (x >> 16);
            return (x + 1);
        }

    }
}
